package com.example.emailWeb.ntru.encrypt;

import com.example.emailWeb.ntru.polynomial.IntegerPolynomial;
import com.example.emailWeb.ntru.polynomial.LongPolynomial;

import java.nio.ByteBuffer;
import java.util.Arrays;

public class NtruProxyUserB {
    int N, p, q, maxM1;
    boolean sparse;
    NtruProxyParameters params;
    public IntegerPolynomial fB, invertfB, b;
    public IntegerPolynomial PKB, CB; // CB是C发过来的；
    public IntegerPolynomial A; //A发过来的；
//    public IntegerPolynomial ;

    private void init() {
        this.N = params.N;
        this.p = params.p;
        this.q = params.q;
        this.maxM1 = params.maxM1;
        this.sparse = params.sparse;
        generateFb();// 计算fB 和 invertfB
    }

    public NtruProxyUserB(NtruProxyParameters param) {
        this.params = param;
        init();
    }

    public NtruProxyUserB() {
        this.params = NtruProxyParameters.APR2011_439;
        init();
    }

    public NtruProxyUserB(IntegerPolynomial fB) {
        this.params = NtruProxyParameters.APR2011_439;
        init();
        this.fB = fB;
    }

    public void generateFb() {
        int Coeffs[] = new int[N];
        Coeffs[0] = 1;
        this.fB = new IntegerPolynomial(Coeffs);
//        System.out.println("fb in generate: " + fB);
        this.invertfB = new IntegerPolynomial(Coeffs);


//        final int N = params.N;
//        int dg = params.dg; // dg = N / 3;
//        Random rng = new SecureRandom();
//        while (true) {
//            IntegerPolynomial fB = DenseTernaryPolynomial.generateRandom(N, dg, dg-1, rng).toIntegerPolynomial();
//            if (fB.isInvertiblePow2()){
//                IntegerPolynomial invertFq = fB.invertFq(q);
//                this.fB = fB;
//                this.invertfB = invertFq;
//
//                System.out.println("fb * invertfb mod q: ");
//                System.out.println(fB.mult(invertfB,q));
//                break;
//            }
//        }


    }


    public void receiveA(IntegerPolynomial receiveA) {
        this.A = receiveA.clone();
        this.b = A.mult(invertfB);//收到A后，立即计算B；
    }

    public IntegerPolynomial getB() {
        if(A==null){
            return null;
        }
        return b;
    }

    public IntegerPolynomial getSkb() {
        //接收方的私钥是fB
        return fB;
    }

    public byte[] decrypt(LongPolynomial CB) {
        IntegerPolynomial res = CB.clone().toIntegerPolynomial();
        res = res.mult(fB);//fA * m
        System.out.println("m before mod3: " + res);
        res.mod3();
        System.out.println("解密出来的明文三元多项式: ");
        System.out.println(res);
        byte[] cM = res.toBinary3Sves(maxM1 > 0);
        return cM;

//        LongPolynomial res = CB.clone();
//        res = res.mult(fB.toLongPolynomial());//fA * m
//        System.out.println("m before mod3: "+res);
//        res.mod3();
//        System.out.println("解密出来的明文三元多项式: ");
//        System.out.println(res);
//        IntegerPolynomial resLong = res.toIntegerPolynomial();
//        byte[] cM = resLong.toBinary3Sves(maxM1>0);
//        return cM;
        // fA * m
//        byte[] cM = res.toBinary3Sves(maxM1>0);
//        return cM;
    }

    public String decrypt(IntegerPolynomial CB) {
        IntegerPolynomial res = CB.clone();
        res = res.mult(fB);//fA * m
//        System.out.println("m before mod3: " + res);
        res.mod3();
//        System.out.println("存放明文数据的三元多项式: " + res);
        byte[] cM = res.toBinary3Sves(maxM1 > 0);
        System.out.println("解密后的明文字节: "+Arrays.toString(cM));
        ByteBuffer buf = ByteBuffer.wrap(cM);
        int mLen = buf.get() & 0xFF;   // llen=1, so read one byte; 代表明文的消息的字节长度；
        byte[] cm = new byte[mLen];
        buf.get(cm); // 得到明文
        System.out.println("解密后的明文字节: "+Arrays.toString(cm));
        return new String(cm);
    }


}
